﻿namespace MicroCloud.Identity
{
    /// <summary>
    /// 业务实现：身份认证模块
    /// </summary>
    public partial class IdentityService
    {
        #region "属性"
        #region "获取 角色组织机构信息查询数据集"
        /// <summary>
        /// 获取 角色组织机构信息查询数据集
        /// </summary>
        public IQueryable<RoleOrganization> RoleOrganizations => RoleOrganizationRepository.QueryAsNoTracking();
        #endregion
        #region "获取 角色组织机构仓储"
        /// <summary>
        /// 获取 角色组织机构仓储
        /// </summary>
        protected IRoleOrganizationStore<Role> RoleOrganizationStore => _provider.GetService<IRoleOrganizationStore<Role>>();
        #endregion

        #endregion

        #region "方法"
        #region "检查角色组织机构信息信息是否存在"
        /// <summary>
        /// 检查角色组织机构信息信息是否存在
        /// </summary>
        /// <param name="predicate">检查谓语表达式</param>
        /// <param name="id">角色组织机构信息编号</param>
        /// <returns>角色组织机构信息是否存在</returns>
        public async Task<bool> CheckRoleOrganizationExists(Expression<Func<RoleOrganization, bool>> predicate, long id = default)
        {
            return await RoleOrganizationRepository.CheckExistsAsync(predicate, id);
        }
        #endregion
        #region "更新角色组织机构信息"
        /// <summary>
        /// 更新角色组织机构信息
        /// </summary>
        /// <param name="dtos">角色组织机构信息集合</param>
        /// <returns>业务操作结果</returns>
        public async Task<OperationResult> UpdateRoleOrganizations(params RoleOrganizationInputDto[] dtos)
        {
            Check.Validate<RoleOrganizationInputDto, long>(dtos, nameof(dtos));

            var userIds = new List<string>();
            OperationResult result = await RoleOrganizationRepository.UpdateAsync(dtos,
                (dto, entity) =>
                {
                    IList<string> userIdsTmp = UserRoleRepository.QueryAsNoTracking(m => m.RoleId == entity.RoleId).Select(m => m.User.Id.ToString()).ToList();
                    var addUserIds = userIdsTmp.Except(userIds);
                    userIds.AddRange(addUserIds);
                    return Task.FromResult(0);
                });
            if (result.Succeeded && userIds.Count > 0)
            {
                var eventData = new OnlineUserCacheRemoveEventData() { UserIds = userIds.ToArray() };
                await EventBus.PublishAsync(eventData);
            }
            return result;
        }
        #endregion
        #region "删除角色组织机构信息"
        /// <summary>
        /// 删除角色组织机构信息
        /// </summary>
        /// <param name="ids">角色组织机构信息编号</param>
        /// <returns>业务操作结果</returns>
        public async Task<OperationResult> DeleteRoleOrganizations(params long[] ids)
        {
            var userIds = new List<string>();
            OperationResult result = await RoleOrganizationRepository.DeleteAsync(ids,
                (entity) =>
                {
                    IList<string> userIdsTmp = UserRoleRepository.QueryAsNoTracking(m => m.RoleId == entity.RoleId).Select(m => m.User.Id.ToString()).ToList();
                    var addUserIds = userIdsTmp.Except(userIds);
                    userIds.AddRange(addUserIds);
                    return Task.FromResult(0);
                });
            if (result.Succeeded && userIds.Count > 0)
            {
                var eventData = new OnlineUserCacheRemoveEventData() { UserIds = userIds.ToArray() };
                await EventBus.PublishAsync(eventData);
            }

            return result;
        }
        #endregion
        #region "设置角色的组织机构"
        /// <summary>
        /// 设置角色的组织机构
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <param name="dtos">角色组织机构DTO集合</param>
        /// <returns>业务操作结果</returns>
        public async Task<OperationResult> SetRoleOrganizations(long roleId, params RoleOrganizationDto[] dtos)
        {
            Role role = await RoleManager.FindByIdAsync(roleId.ToString());
            if (role == null)
            {
                return OperationResult.Error(I18N.T("角色 {0} 不存在", roleId));
            }
            var existOrganizations = RoleOrganizations.Where(m => m.RoleId.Equals(roleId)).Select(m => new RoleOrganizationDto
            {
                OrganizationId = m.OrganizationId,
                Administrator = m.Administrator,
                Leader = m.Leader,
            }).ToList();
            var addOrganizations = dtos.Except(existOrganizations).ToArray();
            var removeOrganizations = existOrganizations.Except(dtos).ToArray();

            if (!addOrganizations.Union(removeOrganizations).Any())
            {
                return OperationResult.Success();
            }

            try
            {
                foreach (var removeOrganization in removeOrganizations)
                {
                    var result = await RoleOrganizationRepository.DeleteBatchAsync(m => m.RoleId.Equals(roleId) && m.OrganizationId.Equals(removeOrganization.OrganizationId));
                    if (!result.Succeeded)
                    {
                        return result.ToOperationResult();
                    }
                }
                foreach (var addOrganization in addOrganizations)
                {
                    var organizationId = OrganizationRepository.QueryAsNoTracking(m => m.Id.Equals(addOrganization.OrganizationId)).Select(m => m.Id).FirstOrDefault();
                    if (Equals(organizationId, default(long)))
                    {
                        throw new InvalidOperationException(I18N.T("组织机构 {0} 不存在", addOrganization.OrganizationId));
                    }
                    RoleOrganization roleOrganization = new() { RoleId = roleId, OrganizationId = addOrganization.OrganizationId, Administrator = addOrganization.Administrator, Leader = addOrganization.Leader };
                    var result = await RoleOrganizationRepository.InsertAsync(roleOrganization);
                    if (!result.Succeeded)
                    {
                        return result.ToOperationResult();
                    }
                }

                var users = UserRoleRepository.QueryAsNoTracking(m => m.RoleId.Equals(roleId)).Select(m => m.User).ToArray();
                if (users.Length > 0)
                {
                    IList<string> userIds = new List<string>();
                    foreach (var user in users)
                    {
                        await UserManager.UpdateSecurityStampAsync(user);
                        userIds.Add(user.Id.ToString());
                    }

                    //更新用户缓存使组织机构生效
                    var eventData = new OnlineUserCacheRemoveEventData() { UserIds = userIds.ToArray() };
                    await EventBus.PublishAsync(eventData);
                }

            }
            catch (InvalidOperationException ex)
            {
                return OperationResult.Error(ex.Message);
            }

            if (addOrganizations.Length > 0 && removeOrganizations.Length == 0)
            {
                return OperationResult.Success(I18N.T("角色 {0} 添加组织机构 {1} 成功", role.Name, addOrganizations.Select(o => o.OrganizationId).ExpandAndToString()));
            }
            if (addOrganizations.Length == 0 && removeOrganizations.Length > 0)
            {
                return OperationResult.Success(I18N.T("角色 {0} 移除组织机构 {1} 成功", role.Name, removeOrganizations.Select(o => o.OrganizationId).ExpandAndToString()));
            }
            return OperationResult.Success(I18N.T("角色 {0} 添加组织机构 {1} 、移除组织机构 {2} 成功。", role.Name, addOrganizations.Select(o => o.OrganizationId).ExpandAndToString(), removeOrganizations.Select(o => o.OrganizationId).ExpandAndToString()));
        }
        #endregion
        #region "设置组织机构的角色"
        /// <summary>
        /// 设置组织机构的角色
        /// </summary>
        /// <param name="organizationId">组织机构编号</param>
        /// <param name="dtos">组织机构角色DTO集合</param>
        /// <returns>业务操作结果</returns>
        public async Task<OperationResult> SetOrganizationRoles(long organizationId, params OrganizationRoleDto[] dtos)
        {
            var org = OrganizationRepository.QueryAsNoTracking(m => m.Id.Equals(organizationId)).FirstOrDefault();
            if (org == null)
            {
                return OperationResult.Error(I18N.T("组织机构 {0} 不存在", organizationId));
            }
            var existRoles = RoleOrganizations.Where(m => m.OrganizationId.Equals(organizationId)).Select(m => new OrganizationRoleDto
            {
                RoleId = m.RoleId,
                Administrator = m.Administrator,
                Leader = m.Leader,
            }).ToList();
            var addRoles = dtos.Except(existRoles).ToArray();
            var removeRoles = existRoles.Except(dtos).ToArray();

            if (!addRoles.Union(removeRoles).Any())
            {
                return OperationResult.Success();
            }

            try
            {
                IList<string> userIds = new List<string>();
                foreach (var removeRole in removeRoles)
                {
                    var result = await RoleOrganizationRepository.DeleteBatchAsync(m => m.RoleId.Equals(removeRole.RoleId) && m.OrganizationId.Equals(organizationId));
                    if (!result.Succeeded)
                    {
                        return result.ToOperationResult();
                    }

                    var users = UserRoleRepository.QueryAsNoTracking(m => Equals(m.RoleId, removeRole.RoleId)).Select(m => m.User).ToArray();
                    if (users.Length > 0)
                    {
                        foreach (var user in users)
                        {
                            await UserManager.UpdateSecurityStampAsync(user);
                            userIds.AddIfNotNull(user.Id.ToString());
                        }
                    }

                }
                foreach (var addRole in addRoles)
                {
                    Role role = await RoleManager.FindByIdAsync(addRole.RoleId.ToString());
                    if (role == null)
                    {
                        return OperationResult.Error(I18N.T("角色 {0} 不存在", addRole.RoleId));
                    }
                    RoleOrganization userOrganization = new() { RoleId = addRole.RoleId, OrganizationId = organizationId, Administrator = addRole.Administrator, Leader = addRole.Leader };
                    var result = await RoleOrganizationRepository.InsertAsync(userOrganization);
                    if (!result.Succeeded)
                    {
                        return result.ToOperationResult();
                    }

                    var users = UserRoleRepository.QueryAsNoTracking(m => Equals(m.RoleId, addRole.RoleId)).Select(m => m.User).ToArray();
                    if (users.Length > 0)
                    {
                        foreach (var user in users)
                        {
                            await UserManager.UpdateSecurityStampAsync(user);
                            userIds.AddIfNotNull(user.Id.ToString());
                        }
                    }

                }

                if (userIds.Count > 0)
                {
                    //更新用户缓存使组织机构生效
                    var eventData = new OnlineUserCacheRemoveEventData() { UserIds = userIds.ToArray() };
                    await EventBus.PublishAsync(eventData);
                }
            }
            catch (InvalidOperationException ex)
            {
                return OperationResult.Error(ex.Message);
            }

            if (addRoles.Length > 0 && removeRoles.Length == 0)
            {
                return OperationResult.Success(I18N.T("组织机构 {0} 添加角色 {1} 成功", org.Name, addRoles.Select(o => o.RoleId).ExpandAndToString()));
            }
            if (addRoles.Length == 0 && removeRoles.Length > 0)
            {
                return OperationResult.Success(I18N.T("组织机构 {0} 移除角色 {1} 成功", org.Name, removeRoles.Select(o => o.RoleId).ExpandAndToString()));
            }
            return OperationResult.Success(I18N.T("组织机构 {0} 添加角色 {1} 、移除角色 {2} 成功。", org.Name, addRoles.Select(o => o.RoleId).ExpandAndToString(), removeRoles.Select(o => o.RoleId).ExpandAndToString()));
        }
        #endregion

        #endregion

    }
}
